package com.wx.rpc.client.core;

import com.wx.rpc.constant.ZKConfig;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.ArrayList;
import java.util.List;


/**
 * @author wx
 * @Description: 发现注册在zk的服务接口
 * @date 2019/3/9 000914:18
 */
public class ZkDiscoveryService implements IDiscoveryService {

    private CuratorFramework curatorFramework;

    List<String> serviceNodes = new ArrayList<String>();


    public ZkDiscoveryService(String address){
        curatorFramework = CuratorFrameworkFactory.builder()
                .connectString(address).sessionTimeoutMs(4000)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
        curatorFramework.start();
    }

    /**
     * @description: 通过serviceName获取ZK注册的服务节点
     * @author: wx
     * @date: 2019/3/9 0009
     * @param serviceName
     * @return: java.lang.String
     */
    @Override
    public String discovery(String serviceName) {
        try {
            // 根据路径获取所有节点
            String serviceUrl = ZKConfig.ZK_REGISTER_PATH + "/" + serviceName;
            serviceNodes = curatorFramework.getChildren().forPath(serviceUrl);
            // 发起服务监听节点，随时更新节点信息列表
            registerWatcher(serviceUrl);
            // 通过负载均衡策略获取服务
            ILoadBanlanceService loadBanlanceService = new RandomLoadBalanceService();
            return loadBanlanceService.selectHost(serviceNodes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;

    }


    /**
     * @description: 监听服务
     * @author: wx
     * @date: 2019/3/9 0009
     * @param path
     * @return: void
     */
    private void registerWatcher(final String path) {
        try {
            //监听数据节点的增删改，可以设置触发的事件
            PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, path, true);

            //事件监听器
            PathChildrenCacheListener pathChildrenCacheListener = new PathChildrenCacheListener() {
                //触发事件
                @Override
                public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
                    // 获取子节点列表
                    serviceNodes = curatorFramework.getChildren().forPath(path);
                }
            };
            // 添加事件监听器
            pathChildrenCache.getListenable().addListener(pathChildrenCacheListener);
            pathChildrenCache.start();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
